package org.internna.expensetracker.model;

import java.util.Set;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.HashSet;
import java.util.TreeSet;
import javax.persistence.FetchType;
import javax.persistence.OneToMany;
import javax.persistence.CascadeType;
import javax.persistence.DiscriminatorValue;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.internna.expensetracker.model.InvestmentPrice;
import org.internna.expensetracker.model.security.UserDetails;
import org.internna.expensetracker.model.InvestmentTransaction;
import org.springframework.roo.addon.entity.RooEntity;
import org.springframework.roo.addon.javabean.RooJavaBean;
import org.springframework.roo.addon.serializable.RooSerializable;
import org.springframework.util.CollectionUtils;
import javax.validation.constraints.NotNull;

@RooEntity
@RooJavaBean
@RooSerializable
@DiscriminatorValue("investment")
public class Investment extends Payee {

    private static final Log logger = LogFactory.getLog(Investment.class);

    private static final long serialVersionUID = 3522888355745107654L;

    @NotNull
    private String productType;

    private String symbol;

    private Locale locale;

    @OneToMany(cascade = CascadeType.REMOVE, fetch = FetchType.LAZY, mappedBy = "investment")
    private Set<InvestmentPrice> prices = new TreeSet<InvestmentPrice>();

    @OneToMany(cascade = CascadeType.REMOVE, fetch = FetchType.LAZY, mappedBy = "investment")
    private Set<InvestmentTransaction> investments = new HashSet<InvestmentTransaction>();

    public final Double getCurrentPrice() {
        return getPrice(new Date());
    }

    public final Double getPrice(Date date) {
        InvestmentPrice price = InvestmentPrice.findInvestmentPrice(this, date);
        return price == null ? 0D : price.getPrice();
    }

    public static List<Investment> findInvestmentsByOwner(UserDetails owner) {
    	return entityManager().createQuery("SELECT p FROM Investment p WHERE owner = :owner", Investment.class)
    		.setParameter("owner", owner)
    		.getResultList();
    }

    public static List<Investment> findInvestmentsByOwnerAndLocale(UserDetails owner, Locale locale) {
    	return entityManager().createQuery("SELECT p FROM Investment p WHERE owner = :owner AND (locale = :locale OR locale IS NULL)", Investment.class)
    		.setParameter("owner", owner)
    		.setParameter("locale", locale)
    		.getResultList();
    }

    public static Investment findByName(String name, UserDetails owner) {
        try {
            return entityManager().createQuery("SELECT p FROM Investment p WHERE name = :name AND owner = :owner", Investment.class).setParameter("name", name).setParameter("owner", owner).getSingleResult();
        } catch (RuntimeException re) {
            logger.warn("Investment [" + name + "] not found in database");
            return null;
        }
    }

    public final void addInvestment(InvestmentTransaction investmentTransaction) {
        if (investmentTransaction != null) {
            if (CollectionUtils.isEmpty(investments)) {
                setInvestments(new TreeSet<InvestmentTransaction>());
            }
            investments.add(investmentTransaction);
            investmentTransaction.setInvestment(this);
            addPrice(investmentTransaction.getPrice());
        }
    }

    public final void addPrice(InvestmentPrice price) {
    	if (price !=  null) {
    		if (prices == null) {
    			prices = new TreeSet<InvestmentPrice>();
    		}
    		prices.add(price);
    		price.setInvestment(this);
    	}
    }

    public final boolean belongsTo(UserDetails user) {
        return user != null && getOwner() != null && user.equals(getOwner());
    }

}
